# Copyright 2025 Silicon Compiler Authors. All Rights Reserved.
import os
import pytest

from siliconcompiler import Chip
from siliconcompiler import NodeStatus
from siliconcompiler.tools.opensta import timing

from siliconcompiler.targets import freepdk45_demo

from tools.inputimporter import importer


@pytest.mark.eda
@pytest.mark.quick
def test_opensta(datadir):
    design = 'foo'
    netlist = os.path.join(datadir, 'lec', f'{design}.vg')
    sdc = os.path.join(datadir, 'lec', f'{design}.sdc')

    chip = Chip(design)
    chip.use(freepdk45_demo)

    flow = 'opensta_timing'
    chip.node(flow, 'opensta', timing)
    chip.set('option', 'flow', flow)

    chip.input(netlist)
    chip.input(sdc)

    # Check that OpenSTA ran successfully
    assert chip.run()

    # Check that the setup and hold slacks are the expected values.
    assert chip.get('metric', 'setupslack', step='opensta', index='0') == -0.220
    assert chip.get('metric', 'holdslack', step='opensta', index='0') == 0.050


@pytest.mark.eda
@pytest.mark.quick
def test_opensta_sdf(datadir):
    design = 'foo'
    netlist = os.path.join(datadir, 'lec', f'{design}.vg')
    sdc = os.path.join(datadir, 'lec', f'{design}.sdc')
    sdf = os.path.join(datadir, 'lec', f'{design}.typical.sdf')

    chip = Chip(design)
    chip.use(freepdk45_demo)

    flow = 'opensta_timing'
    chip.node(flow, 'import', importer)
    chip.node(flow, 'opensta', timing)
    chip.edge(flow, 'import', 'opensta')
    chip.set('option', 'flow', flow)

    chip.input(netlist)
    chip.input(sdc)

    # The SDF file must come in as an input. Use the importer task to get it
    # into the input folder (as if it was generated by a prior tool).
    chip.add('tool', "inputimporter", 'task', 'importer', 'var', 'input_files', sdf)

    # Check that OpenSTA ran successfully
    assert chip.run()

    # Check that the setup and hold slacks are the expected values.
    assert chip.get('metric', 'setupslack', step='opensta', index='0') == -0.890
    assert chip.get('metric', 'holdslack', step='opensta', index='0') == 0.020


@pytest.mark.eda
@pytest.mark.quick
def test_opensta_skip_if_blank_inputs(datadir):
    design = 'blank'

    # Create two blank files which will be passed into the OpenSTA tool driver.
    # The tool driver will recognize that these two files are blank and should
    # skip its step.
    open(f'{design}.vg', 'a')
    open(f'{design}.sdc', 'a')
    netlist = os.path.join(datadir, 'lec', os.path.abspath(f'{design}.vg'))
    sdc = os.path.join(datadir, 'lec', os.path.abspath(f'{design}.sdc'))

    chip = Chip(design)
    chip.use(freepdk45_demo)

    flow = 'opensta_timing'
    chip.node(flow, 'import', importer)
    chip.node(flow, 'opensta', timing)
    chip.edge(flow, 'import', 'opensta')
    chip.set('option', 'flow', flow)

    # The OpenSTA tool driver will only skip the step if the .vg and .sdc file
    # are passed in from the prior step and are both blank. Use the importer
    # task to get these files into the input folder (as if it was generated by
    # a prior tool).
    chip.add('tool', "inputimporter", 'task', 'importer', 'var', 'input_files', [netlist, sdc])

    # Check that that the importer and OpenSTA flow ran successfully
    assert chip.run()

    # Ensure that the OpenSTA step was skipped.
    assert chip.get("record", "status", step="opensta", index="0") == NodeStatus.SKIPPED
